/**create by liuhua at 2019年5月20日 下午7:46:56**/
package com.star.truffle.gateway.config;

import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.gateway.discovery.DiscoveryLocatorProperties;
import org.springframework.cloud.gateway.discovery.GatewayDiscoveryClientAutoConfiguration;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.star.truffle.gateway.filter.PublicGlobalFilter;
import com.star.truffle.gateway.filter.StripPrefixGatewayFilter;
import com.star.truffle.gateway.route.StarRouteLocator;

import reactor.core.publisher.Mono;

@Configuration
@AutoConfigureAfter(GatewayDiscoveryClientAutoConfiguration.class)
@EnableConfigurationProperties
public class RouteLocatorConfiguration {
//  @Bean
//  public RouteLocator myRoutes(RouteLocatorBuilder builder, DiscoveryClient discoveryClient, DiscoveryLocatorProperties properties, StripPrefixGatewayFilter stripPrefix) {
//    discoveryClient.getServices().stream().forEach(serviceId -> {
//      List<ServiceInstance> serviceInstances = discoveryClient.getInstances(serviceId);
//      serviceInstances.stream().filter(instance -> null != instance.getMetadata() && ! instance.getMetadata().isEmpty())
//          .map(serviceInstance1 -> {
//            LocalDateTime appUpTime;
//            String uptime = serviceInstance1.getMetadata().get("app-uptime");
//            if(uptime == null) {
//              appUpTime = LocalDateTime.now().minusYears(1);
//            } else {
//              appUpTime = LocalDateTime.parse(uptime, DateTimeFormatter.ISO_DATE_TIME);
//            }
//            System.out.println(appUpTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
//            serviceInstance1.getMetadata().forEach((k, v) -> {
//              System.out.println(k + "\t" + v);
//            });
//            return 1;
//          })
////          .filter(stringEurekaRequestMetadataMap -> stringEurekaRequestMetadataMap.size() > 0)
//          .collect(Collectors.toList());
//    });
//    
//    RouteLocator routeLocator = builder.routes()
//      .route("route1", r -> r.method(HttpMethod.GET).and().path("/monk/lh/**").uri("lb://star-jymgr").filters(stripPrefix))
//      
//      .route("route2", r -> r.method(HttpMethod.POST).and().header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)
//          .and().readBody(String.class, readBody -> true).and().path("/monk/lh/**").uri("lb://star-jymgr").filters(stripPrefix))
//      
//      .route("route3", r -> r.method(HttpMethod.POST).and().header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
//          .and().readBody(Object.class, readBody -> true).and().path("/monk/lh/**").uri("lb://star-jymgr").filters(stripPrefix))
//      
//      .route("route4", r -> r.method(HttpMethod.GET).and().path("/abc").uri("lb://star-jymgr").filters(new RedirectGatewayFilter(HttpStatus.MOVED_PERMANENTLY, "http://local.cnhnkj.cn:8082/api/getAreaByAreaId?areaId=1")))
//      
//      .route("route5", r -> r.method(HttpMethod.POST).and().path("/a/b/c/d").uri("lb://star-jymgr").filters(new RewriteGatewayFilter("/a/b/c/d", "http://local.cnhnkj.cn:8082/api/getAreaByAreaId")))
//      .build();
//    routeLocator.getRoutes();
//    return routeLocator;
//  }

  private static final String MAX_AGE = "18000L";

  @Bean
  public WebFilter corsFilter() {
    return (ServerWebExchange ctx, WebFilterChain chain) -> {
      ServerHttpRequest request = ctx.getRequest();
      if (!CorsUtils.isCorsRequest(request)) {
        return chain.filter(ctx);
      }
      HttpHeaders requestHeaders = request.getHeaders();
      ServerHttpResponse response = ctx.getResponse();
      HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod();
      HttpHeaders headers = response.getHeaders();
      headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin());
      headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders.getAccessControlRequestHeaders());
      if (requestMethod != null) {
        headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name());
      }
//      headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
      headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, CorsConfiguration.ALL);
      headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE);
      if (request.getMethod() == HttpMethod.OPTIONS) {
        response.setStatusCode(HttpStatus.OK);
        return Mono.empty();
      }
      return chain.filter(ctx);
    };
  }
  
  @Bean
  public StarRouteLocator starRouteLocator(RouteLocatorBuilder builder, DiscoveryClient discoveryClient, ObjectMapper objectMapper, DiscoveryLocatorProperties properties, StripPrefixGatewayFilter stripPrefix) {
    return new StarRouteLocator(builder, discoveryClient, properties, objectMapper, stripPrefix);
  }

  @Bean
  public StripPrefixGatewayFilter stripPrefixGatewayFilter() {
    return new StripPrefixGatewayFilter(1);
  }

  @Bean
  public PublicGlobalFilter publicGlobalFilter() {
    return new PublicGlobalFilter();
  }

}
